package com.rogchen.social.oauthserver.configuration;

import com.rogchen.social.oauthserver.service.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

/**
 * @author Rogchen  rogchen128@gmail.com
 * @description: 认证服务
 * @product: IntelliJ IDEA
 * @create by 19-11-26 09:36
 **/
@Configuration
@EnableAuthorizationServer
public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {


    @Autowired
    private TokenStore tokenStore;

    /**
     * 注入authenticationManager
     * 来支持 password grant type
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                .realm("oauth2-resources") //code授权添加
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()") //allow check token
                .allowFormAuthenticationForClients();
    }

    /**
     * 使用居于内存方式
     *
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("dev")
                .secret("dev")
                .redirectUris("http://baidu.com")//入参是个不定长字符串数组
                .authorizedGrantTypes("authorization_code", "client_credentials", "password", "refresh_token")
                .scopes("all")
                .resourceIds("oauth2-resource")
                .accessTokenValiditySeconds(1200)   //token有效期
                .refreshTokenValiditySeconds(5000) //刷新token的有效期
                .and()
                .withClient("app")
                .secret("app")
                .redirectUris("http://localhost:9092/client/login")//入参是个不定长字符串数组
                .authorizedGrantTypes("authorization_code", "client_credentials", "password", "refresh_token")
                .scopes("all")
                .resourceIds("client")
                .accessTokenValiditySeconds(1200)   //token有效期
                .refreshTokenValiditySeconds(5000); //刷新token的有效期
//        clients.withClientDetails(getClientDetails());
    }

    /**
     * 定义jwt的生成方式
     *
     * @return JwtAccessTokenConverter
     */
//    @Bean
//    public JwtAccessTokenConverter accessTokenConverter() {
//        JwtAccessTokenConverter converter = new JwtAccessTokenConverter() {
//            @Override
//            public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
//                final Map<String, Object> additionalInformation = new HashMap<>();
////                Map userModel = (Map) authentication.getUserAuthentication().getPrincipal();
//                //把用户的主键uin放进去
////                additionalInformation.put("uin", userModel.get("uid"));
////                ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
////                return super.enhance(accessToken, authentication);
//                // 给/oauth/token接口加属性roles,author
//                JSONObject jsonObject = new JSONObject((Map<String, Object>) authentication.getPrincipal());
//                List<Object> authorities = jsonObject.getJSONArray("authoritie");
//                StringBuilder stringBuilder = new StringBuilder();
//                for (Object authority : authorities) {
//                    Map map = (Map) authority;
//                    stringBuilder.append(map.get("authority"));
//                    stringBuilder.append(",");
//                }
//                String roles = stringBuilder.toString();
//                additionalInformation.put("roles", roles.substring(0, roles.length() - 1));
//                additionalInformation.put("author", "sophia");
//                // additionalInfo.put("createTime", df.format(LocalDateTime.now()));
//                ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
//                return accessToken;
//            }
//        };
//        //非对称加密，但jwt长度过长
//        KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource("kevin_key.jks"), "rogchen128".toCharArray())
//                .getKeyPair("kevin_key");
//        converter.setKeyPair(keyPair);
//        return converter;
////        //对称加密
////        converter.setSigningKey("123");
////        return converter;
//    }
    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    /**
     * e6342583-24bd-4ee1-bc6f-9ad46e2ce6a2
     * 票据放于内存中，在生产环境上放在数据库或者redis中。
     *
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                //允许 GET、POST 请求获取 token，即访问端点：oauth/token
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
//                票据存放于内存当中
                .tokenStore(tokenStore)
                .authenticationManager(authenticationManager)
//                必须设置用户详细，否则会出现UserDetailsService is required，或者设置defaultTokenServices，可能因为是使用内存模式才导致这个问题
//                .userDetailsService(myUserDetailsService);
                .tokenServices(defaultTokenServices());
        // 配置JwtAccessToken转换器
//                .accessTokenConverter(accessTokenConverter());
    }

    /**
     * <p>注意，自定义TokenServices的时候，需要设置@Primary，否则报错，</p>
     *
     * @return
     */
    @Primary
    @Bean
    public DefaultTokenServices defaultTokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore());
        tokenServices.setSupportRefreshToken(true);
        //tokenServices.setClientDetailsService(clientDetails());
        // token有效期自定义设置，默认12小时
        tokenServices.setAccessTokenValiditySeconds(60 * 60 * 12);
        // refresh_token默认30天
        tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);
        return tokenServices;

    }
}
